package app.services.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.util.DateParseException;

import app.models.Consulta;
import app.models.FluxoCaixa;
import app.models.Funcionario;
import app.models.Log;
import app.models.enums.StatusConsulta;
import app.models.enums.TipoConsulta;
import app.models.enums.TipoFluxoCaixa;
import app.models.to.Relatorio;
import app.models.to.RelatorioConsulta;
import app.models.to.RelatorioFaturamento;
import app.models.to.RelatorioLog;
import app.repositories.ConsultaRepository;
import app.repositories.FluxoCaixaRepository;
import app.repositories.RelatorioRepository;
import app.services.FuncionarioService;
import app.services.LogService;
import app.services.RelatorioService;
import app.util.DateUtils;
import br.com.caelum.vraptor.ioc.Component;

@Component
public class RelatorioServiceImpl 
	extends GenericServiceImpl<Relatorio, Long> implements RelatorioService {

	private final RelatorioRepository repository;
	private final ConsultaRepository consultaRepository;
	private final FluxoCaixaRepository creditoRepository;
	private final FuncionarioService funcionarioService;
	private final LogService logService;
	
	public RelatorioServiceImpl(RelatorioRepository repository, ConsultaRepository consultaRepository, FluxoCaixaRepository creditoRepository, FuncionarioService funcionarioService, LogService logService) {
		this.repository = repository;
		this.consultaRepository = consultaRepository;
		this.creditoRepository = creditoRepository;
		this.funcionarioService = funcionarioService;
		this.logService = logService;
	}
	
	public List<Consulta> findConsultasUnpaidUntilTodayByFilter(String filter) {
		return repository.findConsultasUnpaidUntilTodayByFilter(filter);
	}
	
	public List<RelatorioConsulta> findRelatorioConsultasByFilters(Consulta consulta) throws ParseException, DateParseException {
		
		Double valorBrutoTotal = 0.0;
		Double valorLiquidoTotal = 0.0;

		List<RelatorioConsulta> relatorioConsultas = new ArrayList<RelatorioConsulta>();
		
		List<Consulta> consultas = consultaRepository.findConsultasByFilters(consulta);
		
		Integer qtAtrasada = 0;
		Integer qtCancelada = 0;
		Integer qtFinalizada = 0;
		Integer qtMarcada = 0;
		Integer qtPaga = 0;
		Integer qtPendente = 0;
		Integer qtRealizada = 0;
		Integer qtTotal = 0;
		
		for (Consulta c : consultas) {
			if (c.getStatus().equals(StatusConsulta.ATRASADA)) {
				qtAtrasada += 1;
			} else if (c.getStatus().equals(StatusConsulta.CANCELADA)) {
				qtCancelada += 1;
			} else if (c.getStatus().equals(StatusConsulta.FINALIZADA)) {
				qtFinalizada += 1;
			} else if (c.getStatus().equals(StatusConsulta.MARCADA)) {
				qtMarcada += 1;
			} else if (c.getStatus().equals(StatusConsulta.PAGA)) {
				qtPaga += 1;
			} else if (c.getStatus().equals(StatusConsulta.PENDENTE)) {
				qtPendente += 1;
			} else if (c.getStatus().equals(StatusConsulta.REALIZADA)) {
				qtRealizada += 1;
			}
			
			qtTotal += 1;
		}
		
		for (Consulta c : consultas) {
			RelatorioConsulta relatorioConsulta = new RelatorioConsulta();
			
			relatorioConsulta.setDataInicial(DateUtils.convertDataStrToDate(consulta.getDataInicial()));
			relatorioConsulta.setDataFinal(DateUtils.convertDataStrToDate(consulta.getDataFinal()));
			
			relatorioConsulta.setTipo(c.getTipo().toString());
			relatorioConsulta.setDataConsulta(DateUtils.convertDataStrToDate(c.getData()));
			
			if (null != c.getDataPagamento()) {
				relatorioConsulta.setDataPagamento(DateUtils.convertDataStrToDate(c.getDataPagamento()));
			}
			
			if (null != c.getEspecialidade()) {
				relatorioConsulta.setNomeEspecialidade(c.getEspecialidade().getNome());
			} else if (null != c.getSubEspecialidade()) {
				relatorioConsulta.setNomeEspecialidade(c.getSubEspecialidade().getNome());
			}
			
			relatorioConsulta.setNomeEspecialista(c.getEspecialista().getUsuario().getNome());
			relatorioConsulta.setNomePaciente(c.getPaciente().getUsuario().getNome());
			relatorioConsulta.setNomeSecretaria(c.getSecretaria().getUsuario().getNome());
			
			if (c.getTipo().equals(TipoConsulta.CONVENIO)) {
				relatorioConsulta.setConvenio(c.getConvenio().getNome());
			}
			
			if (c.getStatus().equals(StatusConsulta.ATRASADA) || 
				c.getStatus().equals(StatusConsulta.FINALIZADA) ||
				c.getStatus().equals(StatusConsulta.PAGA)) {
				
				Funcionario funcionario = funcionarioService.find(c.getIdEspecialista().longValue());
				
				Double percentualComissao = 0.0;
				percentualComissao = funcionario.getPercentualComissao();
				
				if(percentualComissao != null){
					relatorioConsulta.setValorLiquidoConsulta(calculateLiquidValue(percentualComissao, c.getValor()));
				} else {
					relatorioConsulta.setValorLiquidoConsulta(c.getValor());
				}
				
				relatorioConsulta.setValorBrutoConsulta(c.getValor());
				
			} else {
				relatorioConsulta.setValorLiquidoConsulta(0.0);
				relatorioConsulta.setValorBrutoConsulta(0.0);
			}
			
			valorLiquidoTotal += relatorioConsulta.getValorLiquidoConsulta();
			valorBrutoTotal += relatorioConsulta.getValorBrutoConsulta();
			
			relatorioConsulta.setQtAtrasada(qtAtrasada);
			relatorioConsulta.setQtCancelada(qtCancelada);
			relatorioConsulta.setQtFinalizada(qtFinalizada);
			relatorioConsulta.setQtMarcada(qtMarcada);
			relatorioConsulta.setQtPaga(qtPaga);
			relatorioConsulta.setQtPendente(qtPendente);
			relatorioConsulta.setQtRealizada(qtRealizada);
			
			relatorioConsulta.setQtTotal(qtTotal);
			
			relatorioConsulta.setStatus(c.getStatus().toString());
			
			relatorioConsultas.add(relatorioConsulta);
		}
		
		for(RelatorioConsulta item: relatorioConsultas){
			item.setValorBrutoTotal(valorBrutoTotal);
			item.setValorLiquidoTotal(valorLiquidoTotal);
		}
		
		return relatorioConsultas;
	}
	
	private Double calculateLiquidValue(Double percentual, Double valor){
		Double percent = percentual / 100;
		Double valueFuncionario = percent * valor;
		Double value = valor - valueFuncionario;
		
		return value;
	}
	
	public List<RelatorioFaturamento> findRelatorioFaturamentosByFilters(RelatorioFaturamento relatorioFaturamento) 
			throws ParseException, DateParseException {
		
		Double valorBrutoTotal = 0.0;
		Double valorLiquidoTotal = 0.0;
		
		List<RelatorioFaturamento> relatorioFaturamentos = new ArrayList<RelatorioFaturamento>();
		List<RelatorioFaturamento> relFaturamentos = new ArrayList<RelatorioFaturamento>();
		
		List<StatusConsulta> statusList = new ArrayList<StatusConsulta>();
		statusList.add(StatusConsulta.ATRASADA);
		statusList.add(StatusConsulta.PAGA);
		statusList.add(StatusConsulta.FINALIZADA);
		
		List<Consulta> consultas = new ArrayList<Consulta>();
		
		if(relatorioFaturamento.getTipo() != null && !relatorioFaturamento.getTipo().isEmpty()){
			if(relatorioFaturamento.getTipo().equals(String.valueOf(TipoFluxoCaixa.ENTRADA))){
				consultas = consultaRepository.consultasBetweenDatesAndStatus(relatorioFaturamento.getDataInicial(), relatorioFaturamento.getDataFinal(), statusList);
			}
		} else {
			consultas = consultaRepository.consultasBetweenDatesAndStatus(relatorioFaturamento.getDataInicial(), relatorioFaturamento.getDataFinal(), statusList);
		}
		
		if (null != consultas) {
			for (Consulta c : consultas) {
				if(c.getDataPagamento() != null){
					RelatorioFaturamento rf = new RelatorioFaturamento();
					
					rf.setQuantidade(1);
					rf.setTipo(String.valueOf(TipoFluxoCaixa.ENTRADA));
					rf.setDescricao("CONSULTA [" + c.getStatus().toString() + "]");
					rf.setDataCadastro(DateUtils.convertDataUStoBR(c.getDataPagamento()));
					rf.setProduto("CONSULTA");
					
					Funcionario funcionario = funcionarioService.find(c.getIdEspecialista().longValue());
					
					Double percentualComissao = 0.0;
					percentualComissao = funcionario.getPercentualComissao();
					
					if(percentualComissao != null){
						rf.setValorLiquidoItem(calculateLiquidValue(percentualComissao, c.getValor()));
					} else {
						rf.setValorLiquidoItem(c.getValor());
					}
					
					rf.setValorBrutoItem(c.getValor());
					
					valorBrutoTotal += rf.getValorBrutoItem();
					valorLiquidoTotal += rf.getValorLiquidoItem();
					
					relatorioFaturamentos.add(rf);
				}
			}
		}
		
		List<FluxoCaixa> fluxoCaixas;
		
		if(relatorioFaturamento.getTipo() != null){
			fluxoCaixas = creditoRepository.findByPeriodAndByType(relatorioFaturamento.getDataInicial(), relatorioFaturamento.getDataFinal(), TipoFluxoCaixa.valueOf(relatorioFaturamento.getTipo()));
		} else {
			fluxoCaixas = creditoRepository.findByPeriodAndByType(relatorioFaturamento.getDataInicial(), relatorioFaturamento.getDataFinal(), null);
		}
		
		
		if (null != fluxoCaixas) {
			for (FluxoCaixa c : fluxoCaixas) {
				RelatorioFaturamento rf = new RelatorioFaturamento();
				
				rf.setTipo(String.valueOf(c.getTipoFluxoCaixa()));
				rf.setDescricao(c.getDescricao());
				rf.setDataCadastro(DateUtils.convertDataUStoBR(c.getDataCadastro()));
				rf.setQuantidade(c.getQuantidade());
				rf.setProduto(c.getProduto().getNome());
				rf.setValorLiquidoItem(c.getValorTotal());
				rf.setValorBrutoItem(c.getValorTotal());
				
				if(rf.getTipo().equals(TipoFluxoCaixa.SAIDA)){
					valorBrutoTotal -= rf.getValorBrutoItem();
					valorLiquidoTotal -= rf.getValorLiquidoItem();
				} else {
					valorBrutoTotal += rf.getValorBrutoItem();
					valorLiquidoTotal += rf.getValorLiquidoItem();
				}
				
				relatorioFaturamentos.add(rf);
			}
		}
		
		List<Funcionario> funcionarios = new ArrayList<Funcionario>();
		
		if(relatorioFaturamento.getTipo() != null && !relatorioFaturamento.getTipo().isEmpty()){
			if(relatorioFaturamento.getTipo().equals(String.valueOf(TipoFluxoCaixa.SAIDA))){
				funcionarios = funcionarioService.findAllFuncionariosWithSalary();
			}
		} else {
			funcionarios = funcionarioService.findAllFuncionariosWithSalary();
		}
		
		if(funcionarios != null){
			for(Funcionario item: funcionarios){
				RelatorioFaturamento rf = new RelatorioFaturamento();
				
				rf.setTipo(String.valueOf(TipoFluxoCaixa.SAIDA));
				rf.setDescricao("SALÁRIO DE FUNCIONÁRIO");
				rf.setDataCadastro("");
				rf.setQuantidade(1);
				rf.setProduto("SALÁRIO DE FUNCIONÁRIO");
				rf.setValorLiquidoItem(item.getSalario());
				rf.setValorBrutoItem(item.getSalario());
				
				valorBrutoTotal -= rf.getValorBrutoItem();
				valorLiquidoTotal -= rf.getValorLiquidoItem();
				
				relatorioFaturamentos.add(rf);
			}
		}
		
		for (RelatorioFaturamento rf : relatorioFaturamentos) {
			rf.setDataInicial(DateUtils.convertDataUStoBR(relatorioFaturamento.getDataInicial()));
			rf.setDataFinal(DateUtils.convertDataUStoBR(relatorioFaturamento.getDataFinal()));
			
			rf.setValorBrutoTotal(valorBrutoTotal);
			rf.setValorLiquidoTotal(valorLiquidoTotal);
				
			relFaturamentos.add(rf);
		}
		
		return relFaturamentos;
	}

	public List<RelatorioLog> findRelatorioLogsByFilters(RelatorioLog relatorioLog) {
		
		List<RelatorioLog> relatorioLogs = new ArrayList<RelatorioLog>();
		
		List<Log> logs = logService.findLogsByPeriodAndUser(relatorioLog.getDataInicial(), relatorioLog.getDataFinal(), relatorioLog.getUsuario());
				
		if (null != logs) {
			for (Log item : logs) {
				RelatorioLog relatorio = new RelatorioLog();
				
				relatorio.setDataCadastro(item.getDataCadastro());
				relatorio.setDescricao(item.getDescricao());
				relatorio.setHoraCadastro(item.getHoraCadastro());
				relatorio.setUsuario(item.getUsuario().getNome());
				relatorio.setDataFinal(relatorioLog.getDataFinal());
				relatorio.setDataInicial(relatorioLog.getDataInicial());
				
				relatorioLogs.add(relatorio);
			}
		}
		
		return relatorioLogs;
	}
	
}